#pragma once
#include <iostream>
#include <unordered_map>
#include <assert.h>
#include <vector>
#include <fstream>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

struct Question
{
    std::string _num;       // 题目编号
    std::string _title;     // 题目标题
    std::string _star;      // 题目难度
    int _cpu_limit;         // cpu限制
    int _mem_limit;         // 内存限制

    std::string _desc;      // 题目描述
    std::string _header;    // 题目预设给用户在线编辑的代码
    std::string _tail;      // 测试用例，拼接header，形成完整代码
};

const std::string question_list = "./wwwroot/questions.list";
const std::string question_path = "./wwwroot/";

class Model
{
private:
    // 保存题目编号的题目结构的对应关系
    std::unordered_map<std::string, struct Question> _ques;
public:
    Model()
    {
        assert(LoadQuestionList(question_list));
    }
    ~Model(){}

    bool LoadQuestionList(const std::string& question_list)
    {
        // 加载配置文件，question.list + 题目编号文件
        std::ifstream in(question_list);
        if (!in.is_open())
        {
            LOG(FATAL) << " 加载题库失败,请检查是否存在题库文件" << "\n";
            return false;
        }
        std::string out_line;
        while (std::getline(in, out_line))
        {
            std::vector<std::string> tokens; 
            StringUtil::SplitString(out_line, &tokens, " ");
            if (tokens.size() != 5)
            {
                // 切分失败
                LOG(WARNING) << "加载部分题目失败, 请检查文件格式" << "\n";
                continue;
            }
            // 加载题目列表
            Question q;
            q._num = tokens[0];
            q._title = tokens[1];
            q._star = tokens[2];
            q._cpu_limit = atoi(tokens[3].c_str());
            q._mem_limit = atoi(tokens[4].c_str());
            // 加载题目内容
            std::string path = question_path;
            path += q._num;
            path += "/";

            FileUtil::ReadFile(path+"desc.txt", &q._desc, true);
            FileUtil::ReadFile(path+"header.cpp", &q._header, true);
            FileUtil::ReadFile(path+"tail.cpp", &q._tail, true);

            _ques.insert({q._num, q});
        }
        
        in.close();
        LOG(INFO) << "加载题库...成功!" << "\n";
        return true;
    }

    bool GetAllQuestions(std::vector<Question>* out)
    {
        if (_ques.size() == 0)
        {
            LOG(ERROR) << "用户获取题库失败" << "\n";
        }

        for (auto iter: _ques)
        {
            out->push_back(iter.second);    
        }
        
        return true;
    }

    bool GetOneQuestion(const std::string num, struct Question* q)
    {
        const auto& iter = _ques.find(num);
        if (iter == _ques.end())
        {
            LOG(ERROR) << "用户获取题目失败, 题目编号: " << num << "\n";
            return false;
        }
        *q = iter->second;
        return true;
    }
};